/*
 * gntxmms - An XMMS2 curses client
 *
 * Copyright 2007, Sadrul Habib Chowdhury (gntxmms)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer 
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <xmmsclient/xmmsclient.h>
#include <xmmsclient/xmmsclient-glib.h>

#include <stdlib.h>
#include <string.h>

#include "gntxmms.h"
#include "utils.h"

#define print_error g_printerr

static xmmsc_connection_t *conn;

xmmsc_connection_t *gx_init()
{
	conn = xmmsc_init("gntxmms");
	if (!xmmsc_connect(conn, (char*)getenv("XMMS_PATH")))
	{
		fprintf(stderr, "couldn't connect to xmms2d: %s\n",
				xmmsc_get_last_error(conn));
		return NULL;
	}

	xmmsc_mainloop_gmain_init(conn);
	return conn;
}

static void
do_reljump (gint where)
{
	xmmsc_result_t *res;

	res = xmmsc_playlist_set_next_rel (conn, where);
	xmmsc_result_wait (res);

	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't advance in playlist: %s",
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);

	res = xmmsc_playback_tickle (conn);
	xmmsc_result_wait (res);

	if (xmmsc_result_iserror (res)) {
		print_error ("%s", xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
}

void gx_play()
{
	xmmsc_result_t *res;
	
	res = xmmsc_playback_start (conn);
	xmmsc_result_wait (res);
	
	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't start playback: %s",
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
}

void gx_stop()
{
	xmmsc_result_t *res;
	
	res = xmmsc_playback_stop (conn);
	xmmsc_result_wait (res);
	
	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't stop playback: %s",
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
}

void gx_pause()
{
	xmmsc_result_t *res;

	res = xmmsc_playback_pause (conn);
	xmmsc_result_wait (res);

	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't pause playback: %s",
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
}

void gx_play_next()
{
	do_reljump (1);
}

void gx_play_prev()
{
	do_reljump (-1);
}

void gx_seek(int id, gboolean relative);
void gx_jump(int id)
{
	xmmsc_result_t *res;
	res = xmmsc_playlist_set_next (conn, id);
	xmmsc_result_wait (res);
	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't jump to that song: %s",
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);

	res = xmmsc_playback_tickle (conn);
	xmmsc_result_wait (res);

	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't go to next song: %s",
					 xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
	gx_play();
}

void gx_move(int oldp, int newp);
char *gx_info(int id);

char *gx_format_url(const char *url, GFileTest test)
{
	gchar rpath[PATH_MAX], *p, *ret;

	p = strchr (url, ':');
	if (!(p && p[1] == '/' && p[2] == '/')) {
		/* OK, so this is NOT an valid URL */

		if (!realpath (url, rpath)) {
			return NULL;
		}

		if (!g_file_test (url, test)) {
			return NULL;
		}

		ret = g_strdup_printf ("file://%s", rpath);
	} else {
		ret = g_strdup_printf ("%s", url);
	}

	return ret;
}

void gx_add(const char*name, gboolean recursive)
{
	xmmsc_result_t *res;
	gchar *url;
	const char *playlist = NULL;

	url = gx_format_url (name, recursive ? G_FILE_TEST_IS_DIR : G_FILE_TEST_IS_REGULAR);
	if (!url) {
		print_error ("Invalid url");
	}

	res = xmmsc_playlist_add_url (conn, playlist, url);
	xmmsc_result_wait (res);
	g_free (url);

	if (xmmsc_result_iserror (res)) {
		print_error ("Couldn't add %s to playlist: %s\n", name,
		             xmmsc_result_get_error (res));
	}
	xmmsc_result_unref (res);
}

#if 0
static gboolean
res_has_key (xmmsc_result_t *res, const gchar *key)
{
	return xmmsc_result_get_dict_entry_type (res, key) != XMMSC_RESULT_VALUE_TYPE_NONE;
}
#endif

GList *gx_list(const char *format)
{
	xmmsc_result_t *res;
	GList *list = NULL;
	SongInfo *info;

	res = xmmsc_playlist_list_entries(conn, NULL);
	xmmsc_result_wait(res);
	for (; xmmsc_result_list_valid(res); xmmsc_result_list_next(res))
	{
		guint id;
		if (!xmmsc_result_get_uint(res, &id))
			continue;
		info = gx_song_info_st(id);
		if (info) {
			list = g_list_prepend(list, info);
		}
	}

	xmmsc_result_unref(res);
	list = g_list_reverse(list);
	return list;
}

static void
chr_replace(char *str, char src, char dst)
{
	while (*str) {
		if (*str == src)
			*str = dst;
		str++;
	}
}

const char *gx_song_info(int id, const char *format)
{
	xmmsc_result_t *res;
	static gchar print_text[256];
	res = xmmsc_medialib_get_info (conn, id);
	xmmsc_result_wait (res);
	if (xmmsc_result_iserror (res)) {
		return "";
	}

	xmmsc_entry_format (print_text, sizeof(print_text), format, res);
	xmmsc_result_wait(res);

	xmmsc_result_unref (res);
	return print_text;
}

const char *gx_song_artist(int id)
{
	return gx_song_info(id, "${artist}");
}

const char *gx_song_title(int id)
{
	return gx_song_info(id, "${title}");
}

char *gx_song_url(int id)
{
	const char *text = gx_song_info(id, "${url}");
	char *ret;
	ret = *text ? g_path_get_basename(text) : g_strdup("");
	chr_replace(ret, '+', ' ');
	return ret;
}

SongInfo *gx_song_info_st(int id)
{
	const char *cstr;
	char *fstr = NULL;
	SongInfo *info;

	if (id <= 0)
		return NULL;
	
	info = g_hash_table_lookup(songs, &id);

	if (info)
		return info;
	fstr = gx_song_url(id);
	cstr = gx_song_title(id);
	info = g_new0(SongInfo, 1);
	info->mlibid = id;
	info->title = g_strdup((cstr && *cstr) ? cstr : fstr);
	info->artist = g_strdup(gx_song_artist(id));
	info->url = fstr;
	info->ref = 1;
	cstr = gx_song_info(id, "${duration}");
	sscanf(cstr, "%ld", &info->duration);
	g_hash_table_replace(songs, &id, info);
	return info;
}

int gx_current()
{
	guint id;
	xmmsc_result_t *res = xmmsc_playback_current_id(conn);
	xmmsc_result_wait(res);
	if (xmmsc_result_iserror(res) ||
			!xmmsc_result_get_uint(res, &id))
		return -1;
	return id;
}

void gx_song_info_ref(SongInfo *info)
{
	info->ref++;
}

SongInfo *gx_song_info_unref(SongInfo *info)
{
	info->ref--;
	if (info->ref <= 0) {
		g_free(info->title);
		g_free(info->artist);
		g_free(info->url);
		g_free(info);
		info = NULL;
	}
	return info;
}

